-----------------------------------------------------------------
-- 天梯争霸

-- 提示说明在notice配置79
-- 活动开始前x秒，本服发送单人竞技场前100名数据到跨服

-- 人物db
-- db.jjcLadder.useCnt 			已使用体力
-- db.jjcLadder.buyCnt 			已购买体力
-- db.jjcLadder.mobais 			已膜拜列表 [rank]=是否膜拜
-- db.jjcLadder.beMobaiCnt 		历史被膜拜次数

-- common db
-- db.state  					当前阶段
-- db.endTime 					阶段结束时间戳
-- db.uuid2sign 			 	[本服]报名列表 [uuid] = time
-- db.sendDataList  			[本服]同步列表
-- db.lastTopList 				[跨服]上一届前三 可膜拜对象 [rank] = rolebase
-- db.rank2uuid 				[跨服]本次排名 [rank] = uuid
-- db.uuid2rank 				[跨服]本次排名 [uuid] = rank
-- db.logReds 					[跨服]日志红点 [uuid] = 是否有新记录
-- db.uuid2logs 				[跨服]日志记录 [uuid] = {[index]=videoUuid}

-- 活动配置jjcLadder.xlsx
-- 活动时间周六0点-周日23点
-- 活动开始前60秒(周五23点55分-周六0点)为准备阶段，本服同步jjc活动前100名的角色信息到跨服作为活动参赛者
-----------------------------------------------------------------

local Config = require("Config")
local JjcLadderExcel = require("excel.jjcLadder")
local JjcLadderDefine = JjcLadderExcel.define[1]
local MailExcel = require("excel.mail")
local Util = require("common.Util")
local Lang = require("common.Lang")
local CommonDB = require("common.CommonDB")
local Msg = require("core.Msg")
local Timer = require("core.Timer")
local InnerMsg = require("core.InnerMsg")
local ObjHuman = require("core.ObjHuman")
local Broadcast = require("broadcast.Broadcast")
local Grid = require("bag.Grid")
local BagLogic = require("bag.BagLogic")
local CombatLogic = require("combat.CombatLogic")
local CombatDefine = require("combat.CombatDefine")
local CombatPosLogic = require("combat.CombatPosLogic")
local MiddleConnect = require("middle.MiddleConnect")
local MiddleManager = require("middle.MiddleManager")
local MailManager = require("mail.MailManager")
local MailDefine = require("mail.MailIdDefine")
local JjcDB = require("jjc.JjcDB")
local JjcActLogic = require("jjc.JjcActLogic")
local JjcLadderMiddle = require("jjcLadder.JjcLadderMiddle")
local RoleDBLogic = require("role.RoleDBLogic")
local RoleDefine = require("role.RoleDefine")
local RoleLogic = require("role.RoleLogic")
local RoleSystemLogic = require("roleSystem.RoleSystemLogic")
local RoleSystemDefine = require("roleSystem.RoleSystemDefine")
local UnionDBLogic = require("union.UnionDBLogic")
local LiLianLogic = require("dailyTask.LiLianLogic")
local ChengjiuLogic = require("chengjiu.ChengjiuLogic")
local WarReportLogic = require("warReport.WarReportLogic")
local MonsterOutExcel = require("excel.monster").monsterOut
local MonsterExcel = require("excel.monster").monster
local HeroGrid = require("hero.HeroGrid")
local HeroExcel = require("excel.hero")
local ItemDefine = require("bag.ItemDefine")
local RoleSystemExcel = require("excel.roleSystem")
local RoleHeadLogic = require("role.RoleHeadLogic")

STATE_ACT_NO_OPEN = 0  		-- 未开放 可能没开跨服
STATE_ACT_START = 1 		-- 活动进行中
STATE_ACT_READY = 2 		-- 活动准备中-活动未开始
STATE_ACT_SENDDATA = 3 		-- 活动准备中-数据同步

READY_TIME = 60 			-- 准备阶段时间 秒
REFRESH_TIME = 5 			-- 刷新间隔 秒
SENDDATA_PLAYER_CNT = 100 	-- 每个服同步x人
SENDDATA_PER_TIME = 10 		-- 每次同步x个玩家数据
MOBAI_PLAYER_CNT = 3 		-- 可膜拜人数

JJCLADDER_MOBAICNT = JJCLADDER_MOBAICNT or 0 		-- 可膜拜人数
UUID_2_COMBATINFO = UUID_2_COMBATINFO or {}
local TEMP_REWARD_LIST = {{}}

-- 获得活动最新状态 state, startTime, endTime
local function getNewState()
	local nowTime = os.time()
	local weekStartTime = Util.getWeekStartTime(nowTime)
	local scf = JjcLadderDefine.startTime
	local startTime = weekStartTime + (scf.week - 1) * 86400 + scf.hour * 3600 + scf.min * 60
	local ecf = JjcLadderDefine.endTime
	local endTime = weekStartTime + (ecf.week - 1) * 86400 + ecf.hour * 3600 + ecf.min * 60
	if startTime <= nowTime and nowTime < endTime then
		return STATE_ACT_START, endTime
	end
	if nowTime < startTime then
		if startTime - nowTime <= READY_TIME then
			return STATE_ACT_SENDDATA, startTime
		else
			return STATE_ACT_READY, startTime - READY_TIME
		end
	end
	return STATE_ACT_READY, startTime + 7 * 86400 - READY_TIME
end

function getActTime()
	local weekStartTime = Util.getWeekStartTime(os.time())
	local scf = JjcLadderDefine.startTime
	local startTime = weekStartTime + (scf.week - 1) * 86400 + scf.hour * 3600 + scf.min * 60
	local ecf = JjcLadderDefine.endTime
	local endTime = weekStartTime + (ecf.week - 1) * 86400 + ecf.hour * 3600 + ecf.min * 60
	return startTime, endTime
end

-- 获取活动当前状态(显示用)
function getState()
	if not _G.is_middle and not MiddleConnect.IS_MIDDLE_CONNECT then
		return STATE_ACT_NO_OPEN, 0
	end	
	
	local commonDB = getCommonDB()
	if not commonDB.state then
		onTimer()
		commonDB = getCommonDB()
	end
	if commonDB.state == STATE_ACT_START then
		return STATE_ACT_START, commonDB.endTime - os.time()
	end
	if commonDB.state == STATE_ACT_READY then
		return STATE_ACT_READY, commonDB.endTime + READY_TIME - os.time()
	end
	return STATE_ACT_READY, commonDB.endTime - os.time()
end

-- 是否开放
function isOpen(human)
	local state = getState()
	if state == STATE_ACT_NO_OPEN then -- 跨服未启动
		Broadcast.sendErr(human, Lang.MIDDLE_SVR_ERR_CONNECT)
		return 
	end
	-- 判断开放等级
	local config = RoleSystemExcel.roleSystem[RoleSystemDefine.ROLE_SYS_ID_1401]
	local openDay = CommonDB.getServerOpenDay()
	if config and openDay and config.openSvrDay <= openDay then
	else
		return 
	end

--	if not RoleSystemLogic.isOpen(human, RoleSystemDefine.ROLE_SYS_ID_1401, true) then
--		print("  reutrn  111 ", state)
--		return
--	end
	return state
end

-- 检查是否有 配开启 天梯
function isSysOpen()
	local config = RoleSystemExcel.roleSystem[RoleSystemDefine.ROLE_SYS_ID_1401]
	local openDay = CommonDB.getServerOpenDay()
	if config and openDay and config.openSvrDay < openDay then
		return true
	end
	return false
end

-- 红点
function isDot(human)
	-- 可膜拜
	for rank = 1, JJCLADDER_MOBAICNT do
		if not isMobai(human, rank) then
			return true
		end
	end
	-- 有挑战次数
	local state = getState()
	if state == STATE_ACT_START then
		if getLeftCnt(human) > 0 and isSignAct(human.db._id) then
			return true
		end
	end
end

-- 随机奖励
function randomReward(confs)
	local weightSum = 0
	for _, conf in pairs(confs) do
		weightSum = weightSum + conf.weight
	end
	if weightSum < 0 then
		return
	end
	local r = math.random(1, weightSum)
	local tconf = nil
	for _, conf in pairs(confs) do
		if r <= conf.weight then
			tconf = conf 
			break
		end
		r = r - conf.weight
	end
	if not tconf then return end
	local itemCnt = math.random(tconf.itemCnt1, tconf.itemCnt2)
	return tconf.itemID, itemCnt
end

-- 根据名次获取排名奖励
function getRewardByRank(rank)
	for _, conf in ipairs(JjcLadderExcel.reward) do
		if conf.rankMin > rank then
			break
		end
		if rank <= conf.rankMax then
			return conf
		end
	end
end

-- 获取玩家公会旗帜
function getUnionName(unionUuid)
	
	if unionUuid and unionUuid ~= "" then 
		local union = UnionDBLogic.getUnion(unionUuid)
		if union then
			return union.name
		end      
	end
  
    return ""
end

-- 创建人物信息
local function createHumanData(uuid)
	local fakeHuman = CombatLogic.createCombatFakeHuman(uuid)
	if not fakeHuman then return end

	-- 空了就取征战队伍
	local combatHero = CombatPosLogic.getCombatHeros(fakeHuman, CombatDefine.COMBAT_TYPE16 )  -- CombatDefine.COMBAT_TYPE16
	if CombatLogic.isCombatHeroEmpty(combatHero) then 
		CombatPosLogic.copyCombatHeros(fakeHuman, CombatDefine.COMBAT_TYPE1, CombatDefine.COMBAT_TYPE16)
		RoleDBLogic.saveRoleSset(fakeHuman.db)
	end

	local objList, helpList, rolebase, formation, jiban = CombatLogic.getHumanObjList(fakeHuman, CombatDefine.COMBAT_TYPE16) --COMBAT_TYPE16
	if not objList then return end

	rolebase.svrName = Config.SVR_NAME
	rolebase.svrIndex = Config.SVR_INDEX
	rolebase.beMobaiCnt = getBeMobaiCnt(fakeHuman)	-- 历史被点赞数
	rolebase.unionName = getUnionName(rolebase.unionUuid)
	local playerData = {}
	playerData._id = uuid
	playerData.rolebase = rolebase
	playerData.objList = objList
	playerData.helpList = helpList
	playerData.formation = formation
	playerData.jiban = jiban
	return playerData
end

-- 创建NPC信息
local function createNPCData(jjcData)
	local objList, helpList, rolebase, formation, jiban = CombatLogic.getMonsterObjList(jjcData.monsterOutID)
	if not objList then return end

	rolebase.name = jjcData.name 
	rolebase.lv = jjcData.lv 
	rolebase.head = jjcData.head
	rolebase.headFrame = RoleDefine.DEFAULT_HEAD_FRAME
	rolebase.zhandouli = jjcData.zhandouli
	rolebase.uuid = jjcData._id
	rolebase.svrName = Config.SVR_NAME
	rolebase.svrIndex = Config.SVR_INDEX
	rolebase.beMobaiCnt = nil		-- 历史被点赞数
	rolebase.unionName = ""
	local _, mcf = CombatLogic.getMonsterIDByOutID(jjcData.monsterOutID)
	rolebase.body = mcf and mcf.body or 0

	local playerData = {}
	playerData._id = jjcData._id
	playerData.rolebase = rolebase
	playerData.objList = objList
	playerData.helpList = helpList
	playerData.formation = formation	
	playerData.jiban = jiban
	return playerData
end

-- 根据竞技场数据创建传送到跨服的玩家数据
function createPlayerData(jjcData)
	if jjcData.monsterOutID then
		return createNPCData(jjcData)
	else
		return createHumanData(jjcData._id)
	end
end

----------------------------------------------- db --------------------------------------------------
-- 每日刷新
function updateDaily(human)
	if not human.db.jjcLadder then
		return
	end
	human.db.jjcLadder.useCnt = nil
	human.db.jjcLadder.buyCnt = nil
	human.db.jjcLadder.mobais = nil
end

-- 阵容/基础信息变化
function onUpdatePos(human)
	if not isSignAct(human.db._id) then
		return
	end

	local playerData = createHumanData(human.db._id)
	if not playerData then return end

	sendLWPlayerData(playerData)
end

-- 英雄变化
function onUpdateHeroZDL(human, index)
	if not isSignAct(human.db._id) then
		return
	end

	local combatHero = CombatPosLogic.getCombatHeros(human, CombatDefine.COMBAT_TYPE16)  --CombatDefine.COMBAT_TYPE16
	if not combatHero then return end

	local isFind = nil
	for _, heroIndex in pairs(combatHero) do
		if heroIndex == index then
			isFind = true
			break
		end
	end
	if not isFind then return end

	local playerData = createHumanData(human.db._id)
	if not playerData then return end

	sendLWPlayerData(playerData)
end

-- 已使用体力
function getUseCnt(human)
	if not human.db.jjcLadder then
		return 0
	end	
	return human.db.jjcLadder.useCnt or 0
end

-- 
function addUseCnt(human, value)
	if not human.db.jjcLadder then
		human.db.jjcLadder = {}
	end
	local oldValue = human.db.jjcLadder.useCnt or 0
	human.db.jjcLadder.useCnt = oldValue + (value or 1)
end

-- 已购买体力次数
function getBuyCnt(human)
	if not human.db.jjcLadder then
		return 0
	end	
	return human.db.jjcLadder.buyCnt or 0
end

-- 
function addBuyCnt(human, value)
	if not human.db.jjcLadder then
		human.db.jjcLadder = {}
	end
	local oldValue = human.db.jjcLadder.buyCnt or 0
	human.db.jjcLadder.buyCnt = oldValue + (value or 1)
end

-- 剩余可挑战次数
function getLeftCnt(human)
	local maxCnt = JjcLadderDefine.initCnt + getBuyCnt(human)
	local useCnt = getUseCnt(human)
	return math.max(maxCnt - useCnt, 0)
end

-- 剩余购买次数
function getLeftBuyCnt(human)
	local maxCnt = #JjcLadderDefine.buyCosts
	local buyCnt = getBuyCnt(human)
	return math.max(maxCnt - buyCnt, 0)
end

-- 购买体力价格
function getBuyPrice(human)
	local buyCnt = getBuyCnt(human)
	local price = JjcLadderDefine.buyCosts[buyCnt + 1]
	if not price then
		price = JjcLadderDefine.buyCosts[#JjcLadderDefine.buyCosts]
	end 
	return price
end

-- 是否已膜拜
function isMobai(human, rank)
	if not human.db.jjcLadder then
		return
	end
	local mobais = human.db.jjcLadder.mobais 
	if not mobais then return end
	return Util.getBit(mobais, rank) > 0
end

-- 设置膜拜
function setMobai(human, rank)
	if not human.db.jjcLadder then
		human.db.jjcLadder = {}
	end	
	local mobais = human.db.jjcLadder.mobais or 0
	human.db.jjcLadder.mobais = Util.setBit(mobais, rank)
end

-- 是否存在可膜拜
function isMobaiRed(human, mobaiCnt)
	for i = 1, mobaiCnt do
		if not isMobai(human, i) then
			return true
		end
	end
end

-- 刷新剩余时间
function getRefreshLeftTime(human)
	if not human.jjcLadderRefreshTime then
		return 0
	end
	local time = os.time() - human.jjcLadderRefreshTime
	return math.max(0, REFRESH_TIME - time)
end

-- 历史被膜拜次数
function getBeMobaiCnt(human)
	if not human.db.jjcLadder then
		return 0
	end
	return human.db.jjcLadder.beMobaiCnt or 0
end

function setBeMobaiCnt(human, cnt)
	if not human.db.jjcLadder then
		human.db.jjcLadder = {}
	end
	human.db.jjcLadder.beMobaiCnt = cnt
end

function saveCommonDB(data)
	data = data or {}
	CommonDB.updateValue(CommonDB.KEY_JJC_LADDER, data)
end

local TEMP_COMMONDB = {}
function getCommonDB()
	return CommonDB.getValueByKey(CommonDB.KEY_JJC_LADDER) or TEMP_COMMONDB
end

-- 是否有参赛资格
function isSignAct(uuid)
	local commonDB = getCommonDB()
	if commonDB.uuid2sign and commonDB.uuid2sign[uuid] then
		return true
	end
end

------------------------------------------------ msg --------------------------------------------------

-- 查询主界面
function query(human)
	if not isOpen(human) then
		return
	end

	local msgInner = InnerMsg.lw.LW_JJC_LADDER_QUERY
	msgInner.uuid = human.db._id
	InnerMsg.sendMsg(0, msgInner)
end

-- 真打 参数 targetRank|targetUuid
function fight(human, args, combatType)
	local cacheCombatInfo = UUID_2_COMBATINFO[human.db._id]
	if cacheCombatInfo and cacheCombatInfo.time == os.time() then
		return -- 防止连按的情况
	end

	local state = isOpen(human)
	if not state then return end
	if state ~= STATE_ACT_START then
		return Broadcast.sendErr(human, Lang.JJC_LADDER_ERR_TIME)
	end

	if not isSignAct(human.db._id) then
		return Broadcast.sendErr(human, Lang.JJC_LADDER_ERR_JOIN)
	end

	if getLeftCnt(human) < 1 then
		if getLeftBuyCnt(human) > 0 then
			if not buyCnt(human) then
				return
			end
		else
			return Broadcast.sendErr(human, Lang.JJC_LADDER_FIGHT_ERR_CNT)
		end
	end

	local targetRank = tonumber(args[1])
	local targetUuid = args[2]
	if not targetRank or not targetUuid then
		return
	end

	if targetUuid == human.db._id then
		return -- 不能挑战自己哦
	end

	local msgInner = InnerMsg.lw.LW_JJC_LADDER_COMBAT_ASK
	msgInner.uuid = human.db._id
	msgInner.targetUuid = targetUuid
	msgInner.targetRank = targetRank
	InnerMsg.sendMsg(0, msgInner)

	--print("fight", targetUuid, targetRank)
end

-- 战斗结束回调
function onFightEnd(human, result, combatType, cbParam, combatInfo, isSaodang, param)
	print("   onFightEnd   onFightEnd  onFightEnd onFightEnd")
	--print("fight end", result, combatInfo, result)
	if not cbParam or not cbParam.uuid then
		return
	end
	if not param or not param.uuid then
		print(" not  param   ")
	end
	UUID_2_COMBATINFO[cbParam.uuid] = combatInfo

	local rolebase = cbParam.playerData.rolebase
	combatInfo.attacker.name = combatInfo.attacker.name
	combatInfo.defender.name = rolebase.name
	if combatInfo.isWin and cbParam.rank > cbParam.targetRank then
		combatInfo.endParam = cbParam.targetRank .. "|" .. cbParam.rank .. "|" .. cbParam.rank .. "|" .. cbParam.targetRank
	else
		combatInfo.endParam = cbParam.rank .. "|" .. cbParam.targetRank .. "|" .. cbParam.rank .. "|" .. cbParam.targetRank
	end

	local msgRet = Msg.gc.GC_JJC_LADDER_AFTER_FIGHT
	local len = 0
	if getLeftCnt(human) > 0 then
		-- 扣次数 给奖励 
		addUseCnt(human)
		local config = combatInfo.isWin and JjcLadderExcel.winReward or JjcLadderExcel.failReward
		local itemID, itemCnt = randomReward(config)
		if itemID then
			BagLogic.addItem(human, itemID, itemCnt, "jjc_ladder")
			combatInfo.rewardItem = {}
			combatInfo.rewardItem[1] = {itemID, itemCnt}
			len = len + 1
			Grid.makeItem(msgRet.items[len], itemID, itemCnt)
		end
	end


	local state = getState()
	local newRank, newTargetRank = cbParam.rank , cbParam.targetRank
	if state == STATE_ACT_START then
		if combatInfo.isWin and (cbParam.rank > cbParam.targetRank) then
			newRank, newTargetRank = cbParam.targetRank,  cbParam.rank 
		end
	else
		combatInfo.isActEnd = true
	end
	msgRet.result = result
	msgRet.rank = cbParam.rank 
	msgRet.newRank = newRank
	msgRet.targetRank = cbParam.targetRank
	msgRet.targetNewRank = newTargetRank
	RoleLogic.makeRoleBase(combatInfo.attacker, msgRet.atkRole)
	RoleLogic.makeRoleBase(combatInfo.defender, msgRet.defRole)
	msgRet.items[0] = len
	Msg.send(msgRet, human.fd)

	local msgInner = InnerMsg.lw.LW_JJC_LADDER_COMBAT_RESULT
	msgInner.uuid = cbParam.uuid
	msgInner.rank = cbParam.rank 
	msgInner.targetUuid = cbParam.targetUuid
	msgInner.targetRank = cbParam.targetRank
	msgInner.combatInfo = combatInfo
	InnerMsg.sendMsg(0, msgInner)

	if result == CombatDefine.RESULT_WIN then
		LiLianLogic.onCallback(human,LiLianLogic.LILIAN_OUTID4,1)
	end
	-- 战报
    WarReportLogic.add(WarReportLogic.WAR_REPORT_3, combatInfo, cbParam.rank, cbParam.targetRank)
    RoleSystemLogic.onDot(human, RoleSystemDefine.ROLE_SYS_ID_1401)
end

-- 一键挑战
function combatOneKey(human)
	local state = isOpen(human)
	if not state then return end
	if state ~= STATE_ACT_START then
		return Broadcast.sendErr(human, Lang.JJC_LADDER_ERR_TIME)
	end

	ObjHuman.updateDaily(human)
	if getLeftCnt(human) < 1 then
		if getLeftBuyCnt(human) > 0 then
			if not buyCnt(human) then
				return
			end
		else
			return Broadcast.sendErr(human, Lang.JJC_LADDER_FIGHT_ERR_CNT)
		end
	end

	if not isSignAct(human.db._id) then
		return Broadcast.sendErr(human, Lang.JJC_LADDER_ERR_JOIN)
	end

	-- 扣次数 给奖励 名次不变
	addUseCnt(human)

	local itemID, itemCnt = randomReward(JjcLadderExcel.winReward)
	if itemID then
		BagLogic.addItem(human, itemID, itemCnt, "jjc_ladder")
		TEMP_REWARD_LIST[1][1] = itemID
		TEMP_REWARD_LIST[1][2] = itemCnt
		BagLogic.sendItemGetList(human, TEMP_REWARD_LIST)
	end

	sendBuyCnt(human)
	RoleSystemLogic.onDot(human, RoleSystemDefine.ROLE_SYS_ID_1401)

	LiLianLogic.onCallback(human,LiLianLogic.LILIAN_OUTID4,1)
end

-- 购买挑战次数
function buyCnt(human)
	local state = isOpen(human)
	if not state then return end
	if state ~= STATE_ACT_START then
		return Broadcast.sendErr(human, Lang.JJC_LADDER_ERR_TIME)
	end

	ObjHuman.updateDaily(human)
	if getLeftBuyCnt(human) < 1 then
		return Broadcast.sendErr(human, Lang.JJC_LADDER_BUY_ERR_CNT)
	end

	local needPrice = getBuyPrice(human)
	if not ObjHuman.checkRMB(human, needPrice) then
		return  Broadcast.sendErr(human, Lang.COMMON_NO_ZUANSHI) 
	end

	if not isSignAct(human.db._id) then
		return Broadcast.sendErr(human, Lang.JJC_LADDER_ERR_JOIN)
	end

	print("  decZuanshi    ",  -needPrice)
	-- 扣钻石，给次数	
	ObjHuman.decZuanshi(human, -needPrice, "jjc_ladder")
	addBuyCnt(human)
	sendBuyCnt(human)
	RoleSystemLogic.onDot(human, RoleSystemDefine.ROLE_SYS_ID_1401)
	return true
end

function sendBuyCnt(human)
	local msgRet = Msg.gc.GC_JJC_LADDER_BUYCNT
	msgRet.leftCnt = getLeftCnt(human)
	msgRet.leftBuyCnt = getLeftBuyCnt(human)
	msgRet.buyCost = getBuyPrice(human)
	Msg.send(msgRet, human.fd)
end

-- 刷新挑战对象
function refresh(human)
	local state = isOpen(human)
	if not state then return end
	if state ~= STATE_ACT_START then
		return Broadcast.sendErr(human, Lang.JJC_LADDER_ERR_TIME)
	end

	if not isSignAct(human.db._id) then
		return Broadcast.sendErr(human, Lang.JJC_LADDER_ERR_JOIN)
	end

	-- 判断刷新间隔
	local leftTime = getRefreshLeftTime(human)
	if leftTime > 0 then
		return Broadcast.sendErr(human, Util.format(Lang.JJC_LADDER_REFRESH_TOO_QUICK, leftTime))
	end
	human.jjcLadderRefreshTime = os.time()

	query(human)
end

-- 查询膜拜列表
function mobaiQuery(human)
	if not isOpen(human) then
		return
	end

	local msgInner = InnerMsg.lw.LW_JJC_LADDER_MOBAI_QUERY
	msgInner.uuid = human.db._id
	InnerMsg.sendMsg(0, msgInner)
end

-- 膜拜
function mobai(human, rank, isOk)
	if not isOpen(human) then
		return
	end
	if rank < 1 or rank > MOBAI_PLAYER_CNT then
		return
	end
	if isMobai(human, rank) then
		return Broadcast.sendErr(human, Lang.JJC_LADDER_MOBAI_ERR_HAD)
	end

	if isOk then
		setMobai(human, rank)

		for _, item in ipairs(JjcLadderDefine.mobaiItems) do
			local itemID = item[1]
			local itemCnt = item[2]
			BagLogic.addItem(human, itemID, itemCnt, "jjc_ladder_mobai")
		end

		local itemID = JjcLadderDefine.mobaiItems[1][1]
		local itemCnt = JjcLadderDefine.mobaiItems[1][2]
		Broadcast.sendErr(human, Util.format(Lang.JJC_LADDER_MOBAI_SUCCEED, ItemDefine.getValue(itemID, "name"), itemCnt) )
	else
		local msgInner = InnerMsg.lw.LW_JJC_LADDER_MOBAI
		msgInner.uuid = human.db._id
		msgInner.rank = rank 
		InnerMsg.sendMsg(0, msgInner)		
	end
end

-- 查看当前排行/上一期排行榜
function boardQuery(human)
	local state = isOpen(human)
	if not state then return end

	local msgInner = InnerMsg.lw.LW_JJC_LADDER_BOARD
	msgInner.uuid = human.db._id
	InnerMsg.sendMsg(0, msgInner)
end

-- 排名奖励
function queryReward(human, rank)
	local state = isOpen(human)
	if not state then return end

	if rank then
		local msgRet = Msg.gc.GC_JJC_LADDER_REWARD_QUERY
		msgRet.list[0] = #JjcLadderExcel.reward
		for i = 1, msgRet.list[0] do
			local net = msgRet.list[i]
			local conf = JjcLadderExcel.reward[i]
			net.rankMin = conf.rankMin
			net.rankMax = conf.rankMax
			net.items[0] = #conf.reward
			for j = 1, net.items[0] do
				local itemID = conf.reward[j][1]
				local itemCnt = conf.reward[j][2]
				Grid.makeItem(net.items[j], itemID, itemCnt)
			end
		end
		local myConf = getRewardByRank(rank)
		msgRet.rank = nil
		msgRet.myRank = rank 
		msgRet.myReward[0] = myConf and #myConf.reward or 0
		for i = 1, msgRet.myReward[0] do
			local itemID = myConf.reward[i][1]
			local itemCnt = myConf.reward[i][2]
			Grid.makeItem(msgRet.myReward[i], itemID, itemCnt)
		end
		--Msg.trace(msgRet)
		Msg.send(msgRet, human.fd)
	else
		local msgInner = InnerMsg.lw.LW_JJC_LADDER_RANK
		msgInner.uuid = human.db._id
		InnerMsg.sendMsg(0, msgInner)
	end	
end

-- 日志查看
function logQuery(human)
	print("    logQuery !!!!!! " )
	local state = isOpen(human)
	if not state then return end
	if state ~= STATE_ACT_START then
		return Broadcast.sendErr(human, Lang.JJC_LADDER_ERR_TIME)
	end

	local msgInner = InnerMsg.lw.LW_JJC_LADDER_LOG
	msgInner.uuid = human.db._id
	InnerMsg.sendMsg(0, msgInner)
end

-- 查看录像
function repeatVideo(human, videoUuid)
	local state = isOpen(human)
	if not state then return end
	if state ~= STATE_ACT_START then
		return Broadcast.sendErr(human, Lang.JJC_LADDER_ERR_TIME)
	end

	local msgInner = InnerMsg.lw.LW_JJC_LADDER_REPEAT_VIDEO
	msgInner.uuid = human.db._id
	msgInner.videoUuid = videoUuid
	InnerMsg.sendMsg(0, msgInner)	
end

-------------------------------------- middle -------------------------------------------
local function cmpRank(a, b)
	return a.roleBase.rank < b.roleBase.rank
end

-- 封装 英雄
local function fontHeroList(net,data)
    local len = 0
    local monsterOutID = data.monsterOutID
    if monsterOutID then
        for k,v in ipairs(MonsterOutExcel[monsterOutID].member) do
            if v[1] > 0 then
                len = len + 1
                HeroGrid.makeHeroSimpleByMonsterID(net[len],v[1],{lv = v[2]})
            end
        end
    else
        for i = 1,CombatDefine.COMBAT_HERO_CNT do
            local obj = data.objList[i]
            if obj then
                len = len + 1
				if HeroExcel.hero[obj.id] then					
					HeroGrid.makeHeroSimpleByID(net[len],obj.id, obj.bagIndex,{lv = obj.lv,star = obj.star})
				else
					HeroGrid.makeHeroSimpleByMonsterID(net[len],obj.id,{lv = obj.lv,star = obj.star})
				end                
            end
        end
    end
    net[0] = len
end


-- 返回主界面信息 
function WL_JJC_LADDER_QUERY(uuid, targetList, mobaiCnt, logRed, myRank)
	local human = ObjHuman.onlineUuid[uuid]
	if not human then return end

	ObjHuman.updateDaily(human)
	local state, leftTime = getState()
	
	local msgRet = Msg.gc.GC_JJC_LADDER_QUERY
	local dataNet = msgRet.data
	dataNet.state =  state
	print("  state    getState() dataNet.state ",  state   , dataNet.state)
	dataNet.leftTime = leftTime
	dataNet.mobaiRed = isMobaiRed(human, mobaiCnt) and 1 or 0
	dataNet.logRed = logRed
	local startTime,endTime = getActTime()
	local cleanTime = Util.getDayStartTime(endTime + 60 * 60 * 24)
	if state == STATE_ACT_START then
		dataNet.list[0] = #targetList
		if dataNet.list[0] > 1 then
			table.sort(targetList, cmpRank)
		end
		for i = 1, dataNet.list[0] do
			local rankNet = dataNet.list[i]
			local rankData = targetList[i].roleBase
			rankNet.rank = rankData.rank
			rankNet.uuid = rankData.uuid
			rankNet.name = rankData.name 
			rankNet.svrName = rankData.svrName
			rankNet.body = rankData.body or 0
			rankNet.head = rankData.head
			rankNet.headFrame = rankData.headFrame or RoleDefine.DEFAULT_HEAD_FRAME
			rankNet.zhandouli = rankData.zhandouli 
			rankNet.unionName = rankData.unionName
			rankNet.svrIndex = rankData.svrIndex or 0

			fontHeroList(rankNet.heroList, targetList[i])

		end
	else
		dataNet.list[0] = 0
		if (state == STATE_ACT_READY and os.time() >= startTime and os.time() < cleanTime) then
			dataNet.state = 3
			if #targetList > 0 then
				dataNet.list[0] = #targetList
				if dataNet.list[0] > 1 then
					table.sort(targetList, cmpRank)
				end
				for i = 1, dataNet.list[0] do
					local rankNet = dataNet.list[i]
					local rankData = targetList[i].roleBase
					rankNet.rank = rankData.rank
					rankNet.uuid = rankData.uuid
					rankNet.name = rankData.name 
					rankNet.svrName = rankData.svrName
					rankNet.body = rankData.body or 0
					rankNet.head = rankData.head
					rankNet.headFrame = rankData.headFrame or RoleDefine.DEFAULT_HEAD_FRAME
					rankNet.zhandouli = rankData.zhandouli 
					rankNet.unionName = rankData.unionName
					rankNet.svrIndex = rankData.svrIndex or 0
		
					fontHeroList(rankNet.heroList, targetList[i])
		
				end
			end
		end
	end
	dataNet.myRank = myRank
	dataNet.leftCnt = getLeftCnt(human)
	dataNet.leftBuyCnt = getLeftBuyCnt(human)
	dataNet.buyCost = getBuyPrice(human)
	--Msg.trace(msgRet)
	Msg.send(msgRet, human.fd)

	human.jjcLadderTargetList = targetList
	JJCLADDER_MOBAICNT = mobaiCnt
end

-- 行为检测
function WL_JJC_LADDER_RANK(uuid, rank)
	local human = ObjHuman.onlineUuid[uuid]
	if not human then return end

	queryReward(human, rank)
end

-- 膜拜查询
function WL_JJC_LADDER_MOBAI_QUERY(uuid, list)
	local human = ObjHuman.onlineUuid[uuid]
	if not human then return end

	local msgRet = Msg.gc.GC_JJC_LADDER_MOBAI_QUERY
	msgRet.list[0] = list and #list or 0
	for i = 1, msgRet.list[0] do
		local net = msgRet.list[i]
		local rankData = list[i]
		net.rank = i 
		net.uuid = rankData.uuid 
		net.name = rankData.name 
		net.svrName = rankData.svrName
		net.head = rankData.head
		net.headFrame = rankData.headFrame or RoleDefine.DEFAULT_HEAD_FRAME
		net.body = rankData.body or 0
		net.cnt = rankData.beMobaiCnt or 0
		net.isMobai = isMobai(human, i) and 1 or 0
		net.svrIndex = rankData.svrIndex or 0
	end
	--Msg.trace(msgRet)
	Msg.send(msgRet, human.fd)
end

-- 膜拜点赞
function WL_JJC_LADDER_MOBAI(uuid, rank)
	local human = ObjHuman.onlineUuid[uuid]
	if not human then return end

	mobai(human, rank, true)
	RoleSystemLogic.onDot(human, RoleSystemDefine.ROLE_SYS_ID_1401)
end

-- 封装排行榜结构体
local function fontBoardNet(net, data, db)
	if data.rank and data.uuid then
		net.rank = data.rank 
		net.uuid = data.uuid  
		net.head = data.head
		net.headFrame = data.headFrame or RoleDefine.DEFAULT_HEAD_FRAME
		net.name = data.name 
		net.svrName = data.svrName
		net.unionName = data.unionName or ""
		net.zhandouli = data.zhandouli
	else
		local union = UnionDBLogic.getUnion(db.unionUuid)
		net.rank = 0 
		net.uuid = db._id 
		net.head = db.head
		net.headFrame = db.headFrame or RoleDefine.DEFAULT_HEAD_FRAME
		net.name = db.name 
		net.svrName = Config.SVR_NAME
		net.unionName = union and union.name or ""
		net.zhandouli = db.zhandouli
	end
end

-- 排行榜查询
function WL_JJC_LADDER_BOARD(uuid, list, myData)
	local human = ObjHuman.onlineUuid[uuid]
	if not human then return end

	local msgRet = Msg.gc.GC_JJC_LADDER_BOARD
	msgRet.list[0] = list and #list or 0
	for i = 1, msgRet.list[0] do
		local rankData = list[i]
		RoleLogic.makeRoleBase(rankData, msgRet.list[i].rolebase)
		msgRet.list[i].rolebase.serverName =  rankData.serverName and  rankData.serverName or  msgRet.list[i].rolebase.serverName   -- and msgRet.list[i].rolebase.svrName or rankData.serverName
		msgRet.list[i].unionName = rankData.unionName or ""
	end
	if myData.uuid then
		RoleLogic.makeRoleBase(myData, msgRet.myData.rolebase)
		msgRet.myData.unionName = myData.unionName or ""
	else
		RoleLogic.makeRoleBase(human.db, msgRet.myData.rolebase)
		msgRet.myData.unionName  = getUnionName(human.db.unionUuid)
	end
	msgRet.myRank = myData.rank or 0
	--Msg.trace(msgRet)
	Msg.send(msgRet, human.fd)
end

-- 战斗请求返回
function WL_JJC_LADDER_COMBAT_ASK(uuid, rank, targetUuid, targetRank, playerData)
	local human = ObjHuman.onlineUuid[uuid]
	if not human then return end

	-- 开打
	local cbParam = {}
	cbParam.uuid = uuid
	cbParam.rank = rank 
	cbParam.targetUuid = targetUuid
	cbParam.targetRank = targetRank
	cbParam.playerData = playerData

	local param = {}
	param.defender = playerData.objList
	param.defHelp = playerData.helpList
	param.defRBase = playerData.rolebase
	param.defFormation = playerData.formation
	param.defJiban = playerData.jiban
	print("  WL_JJC_LADDER_COMBAT_ASK               !!!!!!  ", cbParam.uuid)
	CombatLogic.combatBegin(human, 1001, param, CombatDefine.COMBAT_TYPE15, cbParam)
end

-- 战斗结果播放
function WL_JJC_LADDER_COMBAT_RESULT(uuid, rank, targetUuid, targetRank)
	local human = ObjHuman.onlineUuid[uuid]
	if not human then return end

	local cacheCombatInfo = UUID_2_COMBATINFO[uuid]
	UUID_2_COMBATINFO[uuid] = nil

	if cacheCombatInfo then		
--        CombatLogic.addCombatCache(human.db._id, cacheCombatInfo, nil, true)
 --       CombatLogic.sendCombatData(human, cacheCombatInfo)
	end	
end


function  fontJJCLog(net,  log)
	net.time = log.time 
	RoleLogic.makeRoleBase(log.attacker, net.attacker )
	RoleLogic.makeRoleBase(log.defender, net.defender)
	net.isWin = log.isWin and 1 or 0
	net.videoUuid = log.videoUuid or ""
	net.atkRank = log.atkRank
	net.defRank = log.defRank
	net.atkSvr = log.attacker.serverName
	net.defSvr = log.defender.serverName
end

-- 战斗日志
function WL_JJC_LADDER_LOG(uuid, logs, godLogs)
	local human = ObjHuman.onlineUuid[uuid]
	if not human then return end
	local msgRet = Msg.gc.GC_JJC_LADDER_LOG
	msgRet.list[0] = logs and #logs or 0
	for i = 1, msgRet.list[0] do
		local net = msgRet.list[i]
		fontJJCLog(net, logs[i])
	end
	msgRet.godList[0] = godLogs and #godLogs or 0
	msgRet.godList[0] = msgRet.godList[0] < 10 and msgRet.godList[0] or 10
	for i = 1, msgRet.godList[0] do
		local net = msgRet.godList[i]
		fontJJCLog(net, godLogs[i])
	end
--	Msg.trace(msgRet)
	Msg.send(msgRet, human.fd)
end

-- 战斗回放
function WL_JJC_LADDER_REPEAT_VIDEO(uuid, combatInfo)
	local human = ObjHuman.onlineUuid[uuid]
	if not human then return end

	if not next(combatInfo) then
		Broadcast.sendErr(human, Lang.COMBAT_ERR_NOT_VIDEO)
	else
		CombatLogic.repeatCombat(human, combatInfo)
	end
end

-- 比赛结果 发奖励
local FieldJjcFinal = {lv = 1}
function WL_JJC_LADDER_FINAL_RESULT(list)
	local mailConfig = MailExcel.mail[MailDefine.MAIL_ID_JJC_LADDER]
	local title = mailConfig.title
	local senderName = mailConfig.senderName	
	local needLv = 0 -- RoleSystemLogic.getOpenLv(RoleSystemDefine.ROLE_SYS_ID_10012)
	for _, conf in ipairs(JjcLadderExcel.reward) do
		for rank = conf.rankMin, conf.rankMax do
			local uuid = list[rank]
			local db = uuid and RoleDBLogic.getDb(uuid, FieldJjcFinal)
			if db and (db.lv >= needLv) then
				-- 发邮件
				local content = Util.format(mailConfig.content, rank)
				MailManager.add(MailManager.SYSTEM, uuid, title, content, conf.reward, senderName)

				-- 回调
				LiLianLogic.onCallbackByUuid(uuid,LiLianLogic.LILIAN_OUTID3,1,rank,nil,true)
			end
		end
	end
end

--
function WL_JJC_LADDER_MOBAI_CNT(mobaiCnt)
	JJCLADDER_MOBAICNT = mobaiCnt
	--print("JJCLADDER_MOBAICNT",JJCLADDER_MOBAICNT)
end

-- 点赞数同步
local FieldJjcBemobai = {jjcLadder = 1}
function WL_JJC_LADDER_BEMOBAICNT(uuid, beMobaiCnt)
	local db = RoleDBLogic.getDb(uuid, FieldJjcBemobai)
	if db then
		db.jjcLadder = db.jjcLadder or {}
		db.jjcLadder.beMobaiCnt = beMobaiCnt
		RoleDBLogic.saveRoleSset(db)
	end
end

-- 刷新红点
function updateReds()
	for _, human in pairs(ObjHuman.onlineUuid) do
		if human.fd then
			RoleSystemLogic.onDot(human, RoleSystemDefine.ROLE_SYS_ID_1401)
		end
	end
end

local function getChengHaoIDByRank(rank) 
	if rank > 3 then
		return 0
	end

	local config = JjcLadderExcel.godWarBoard[rank]
	if config then
		local chenghao = config.reward[#config.reward]
		return chenghao
	end
	return 0
end

function WL_JJC_LADDER_CHENGHAO_DEL(msg)
	for uuid, db in pairs(msg.list) do
		if db.svrIndex == Config.SVR_INDEX then
			local chenghao = getChengHaoIDByRank(db.rank)
			if chenghao and chenghao > 0 then				
				RoleHeadLogic.unActive(uuid, RoleHeadLogic.HEAD_TYPE_4, chenghao)
			end
		end
	end
end

------------------------------------- 活动状态变化 ------------------------------------------
-- 活动开始
function onActStart()
	if _G.is_middle then
		return JjcLadderMiddle.onActStart()
	end

	Timer.addLater(1, updateReds)
end

-- 活动结束
function onActEnd()
	if _G.is_middle then
		return JjcLadderMiddle.onActEnd()
	end

	local commonDB = getCommonDB()
	commonDB.uuid2sign = nil
	commonDB.sendDataList = nil
	saveCommonDB(commonDB)

	Timer.addLater(1, updateReds)
end

-- 活动准备开始 
function onActReady()
	if _G.is_middle then
		return	JjcLadderMiddle.onActReady()
	end	
	print(" onActReady  !!! go ")
	local openDay = CommonDB.getServerOpenDay() 
	if not openDay then
		return
	end
	if openDay < 3 then
		return
	end

	local commonDB = getCommonDB()
	commonDB.sendDataList = {}
	commonDB.uuid2sign = {}
	for i = SENDDATA_PLAYER_CNT, 1, -1 do
		local jjcData = JjcDB.RANK_2_JJCDATA[i]
		if jjcData then
			local listLen = #commonDB.sendDataList
			commonDB.sendDataList[listLen + 1] = jjcData
		end
	end
	saveCommonDB(commonDB)
end

-- l->w
function sendLWPlayerData(playerData)
	local msgInner = InnerMsg.lw.LW_JJC_LADDER_SENDDATA
	msgInner.player = playerData
	InnerMsg.sendMsg(0, msgInner)		
end

-- 同步玩家数据到跨服 l->w
function sendData2Middle()
	local commonDB = getCommonDB()
	if not commonDB.sendDataList then
		return
	end

	local nowTime = os.time()
	for i = 1, SENDDATA_PER_TIME do
		local listLen = #commonDB.sendDataList
		local jjcData = commonDB.sendDataList[listLen]
		if not jjcData then break end

		commonDB.sendDataList[listLen] = nil
		local playerData = createPlayerData(jjcData)
		if playerData then
			sendLWPlayerData(playerData)
			commonDB.uuid2sign[playerData._id] = nowTime	
		end
	end

	-- 全部发完，清空
	if #commonDB.sendDataList < 1 then
		commonDB.sendDataList = nil
	end
	saveCommonDB(commonDB)
end

function getCleanUpTime()
	local _,endTime = getActTime()
	return Util.getDayStartTime(endTime + 60 * 60 * 24)
end

-- 定时器
TEMP_TIMER_STAMPTIME = TEMP_TIMER_STAMPTIME or nil
function onTimer()	
	if not TEMP_TIMER_STAMPTIME then
		_, TEMP_TIMER_STAMPTIME = getNewState()
	end

	local nowTime = os.time()
	local commonDB = getCommonDB()
	if (not commonDB.endTime) or 
		(commonDB.endTime <= nowTime) or
		(commonDB.endTime ~= TEMP_TIMER_STAMPTIME) then
		local oldState = commonDB.state
		local state, endTime = getNewState()  
		print("  onTimer   ", state, endTime)
		commonDB.state = state
		commonDB.endTime = endTime
		TEMP_TIMER_STAMPTIME = endTime
		saveCommonDB(commonDB)

		--print("jjcLadder state",state,oldState,endTime)

		if state == STATE_ACT_START then
			onActStart()
		elseif state == STATE_ACT_READY then
			onActEnd()
		elseif state == STATE_ACT_SENDDATA then
			onActReady()
		end
	end

	if _G.is_middle then
		-- 跨服
		if not commonDB.cleanTime then			
			commonDB.cleanTime = getCleanUpTime()
			saveCommonDB(commonDB)
		end

	--	print(" endTime,   cleanTime   ",nowTime , commonDB.cleanTime- nowTime, nowTime > commonDB.cleanTime , Util.getWeekDay(commonDB.endTime),  Util.getWeekDay(cleanTime) ,os.time(), os.time() >= commonDB.endTime )
		if nowTime > commonDB.cleanTime then
			print("  read  clean  up")
			JjcLadderMiddle.resetDbActEnd()		
		end
	else
		-- 本服
		sendData2Middle()
	end
end

-- 返回活动列表的状态
function getActState()
	if not MiddleConnect.IS_MIDDLE_CONNECT then
		return JjcActLogic.STATE_NOOPEN, 0
	end	

	local state, leftTime = getState()
	if state == STATE_ACT_START then
		-- 如果是 是当天开服 则没有走 0点逻辑 没有对手 没有天梯比赛
		local openDay = CommonDB.getServerOpenDay()
		if not openDay then
			return JjcActLogic.STATE_NOOPEN, 0
		end
		if openDay and openDay <= 4 then
			return JjcActLogic.STATE_NOOPEN, 0
		end
		return JjcActLogic.STATE_START, leftTime
	end
	return JjcActLogic.STATE_READY, leftTime
end

-- 描述
function getActDesc(desc)
	if not MiddleConnect.IS_MIDDLE_CONNECT then
		return Lang.MIDDLE_SVR_ERR_CONNECT
	end		
	return desc
end